using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BanZuiCloudControlAgent.Core.Mqtt.Models;
using BanZuiCloudControlAgent.Utils.Common;
using BanZuiCloudControlAgent.Utils.Logging;

namespace BanZuiCloudControlAgent.Core.Mqtt.MessageCache
{
    /// <summary>
    /// MQTT消息缓存，用于缓存MQTT消息，实现本地消息缓存和重发机制
    /// </summary>
    public class MqttMessageCache
    {
        private readonly NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();
        private readonly string _cacheDirectory;
        private readonly int _maxCacheSize;
        private readonly SemaphoreSlim _cacheLock = new SemaphoreSlim(1, 1);
        private readonly List<CachedMessage> _messageQueue = new List<CachedMessage>();
        private bool _isInitialized;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="maxCacheSize">最大缓存消息数量</param>
        public MqttMessageCache(int maxCacheSize = 1000)
        {
            _maxCacheSize = maxCacheSize;
            _cacheDirectory = Path.Combine(ConfigurationManager.GetTempFilePath("MqttCache"), "Messages");
            _isInitialized = false;
        }

        /// <summary>
        /// 初始化缓存
        /// </summary>
        public async Task InitializeAsync()
        {
            try
            {
                await _cacheLock.WaitAsync();

                if (_isInitialized)
                {
                    return;
                }

                // 创建缓存目录
                if (!Directory.Exists(_cacheDirectory))
                {
                    Directory.CreateDirectory(_cacheDirectory);
                }

                // 加载现有缓存消息
                await LoadCachedMessagesAsync();

                _isInitialized = true;
                _logger.Info($"MQTT消息缓存初始化完成，当前缓存消息数量: {_messageQueue.Count}");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "初始化MQTT消息缓存失败");
            }
            finally
            {
                _cacheLock.Release();
            }
        }

        /// <summary>
        /// 添加消息到缓存
        /// </summary>
        /// <param name="message">消息对象</param>
        /// <param name="topic">主题</param>
        /// <param name="qosLevel">服务质量级别</param>
        /// <param name="retain">是否保留消息</param>
        /// <returns>是否添加成功</returns>
        public async Task<bool> AddMessageAsync(BaseMessageModel message, string topic, int qosLevel = 0, bool retain = false)
        {
            try
            {
                if (message == null)
                {
                    return false;
                }

                await _cacheLock.WaitAsync();

                // 检查缓存是否已满
                if (_messageQueue.Count >= _maxCacheSize)
                {
                    // 移除最旧的消息
                    RemoveOldestMessage();
                }

                // 创建缓存消息
                var cachedMessage = new CachedMessage
                {
                    Id = Guid.NewGuid().ToString(),
                    MessageId = message.MessageId,
                    MessageType = message.MessageType,
                    Topic = topic,
                    Payload = JsonHelper.Serialize(message),
                    QosLevel = qosLevel,
                    Retain = retain,
                    Timestamp = DateTime.Now,
                    RetryCount = 0
                };

                // 添加到内存队列
                _messageQueue.Add(cachedMessage);

                // 保存到文件
                await SaveMessageToFileAsync(cachedMessage);

                _logger.Debug($"添加消息到缓存，消息ID: {message.MessageId}, 主题: {topic}, 消息类型: {message.MessageType}");
                return true;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"添加消息到缓存失败，消息ID: {message?.MessageId}");
                return false;
            }
            finally
            {
                _cacheLock.Release();
            }
        }

        /// <summary>
        /// 获取待发送的消息
        /// </summary>
        /// <param name="count">获取数量</param>
        /// <returns>待发送的消息列表</returns>
        public async Task<List<CachedMessage>> GetPendingMessagesAsync(int count = 10)
        {
            try
            {
                await _cacheLock.WaitAsync();

                // 按时间戳排序，获取指定数量的消息
                var messages = _messageQueue
                    .OrderBy(m => m.Timestamp)
                    .Take(count)
                    .ToList();

                return messages;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "获取待发送的消息失败");
                return new List<CachedMessage>();
            }
            finally
            {
                _cacheLock.Release();
            }
        }

        /// <summary>
        /// 标记消息为已发送
        /// </summary>
        /// <param name="messageId">消息ID</param>
        /// <returns>是否标记成功</returns>
        public async Task<bool> MarkMessageAsSentAsync(string messageId)
        {
            try
            {
                await _cacheLock.WaitAsync();

                // 查找消息
                var message = _messageQueue.FirstOrDefault(m => m.MessageId == messageId);
                if (message == null)
                {
                    return false;
                }

                // 从队列中移除
                _messageQueue.Remove(message);

                // 删除文件
                DeleteMessageFile(message.Id);

                _logger.Debug($"标记消息为已发送，消息ID: {messageId}");
                return true;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"标记消息为已发送失败，消息ID: {messageId}");
                return false;
            }
            finally
            {
                _cacheLock.Release();
            }
        }

        /// <summary>
        /// 标记消息为发送失败
        /// </summary>
        /// <param name="messageId">消息ID</param>
        /// <param name="maxRetries">最大重试次数</param>
        /// <returns>是否标记成功</returns>
        public async Task<bool> MarkMessageAsFailedAsync(string messageId, int maxRetries = 3)
        {
            try
            {
                await _cacheLock.WaitAsync();

                // 查找消息
                var message = _messageQueue.FirstOrDefault(m => m.MessageId == messageId);
                if (message == null)
                {
                    return false;
                }

                // 增加重试次数
                message.RetryCount++;

                // 如果超过最大重试次数，则移除
                if (message.RetryCount > maxRetries)
                {
                    _messageQueue.Remove(message);
                    DeleteMessageFile(message.Id);
                    _logger.Warn($"消息发送失败且超过最大重试次数，已移除，消息ID: {messageId}");
                }
                else
                {
                    // 更新文件
                    await SaveMessageToFileAsync(message);
                    _logger.Debug($"标记消息为发送失败，消息ID: {messageId}, 重试次数: {message.RetryCount}");
                }

                return true;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"标记消息为发送失败失败，消息ID: {messageId}");
                return false;
            }
            finally
            {
                _cacheLock.Release();
            }
        }

        /// <summary>
        /// 清空缓存
        /// </summary>
        public async Task ClearCacheAsync()
        {
            try
            {
                await _cacheLock.WaitAsync();

                // 清空内存队列
                _messageQueue.Clear();

                // 删除所有缓存文件
                if (Directory.Exists(_cacheDirectory))
                {
                    foreach (var file in Directory.GetFiles(_cacheDirectory, "*.msg"))
                    {
                        try
                        {
                            File.Delete(file);
                        }
                        catch (Exception ex)
                        {
                            _logger.Error(ex, $"删除缓存文件失败: {file}");
                        }
                    }
                }

                _logger.Info("MQTT消息缓存已清空");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "清空MQTT消息缓存失败");
            }
            finally
            {
                _cacheLock.Release();
            }
        }

        /// <summary>
        /// 获取缓存消息数量
        /// </summary>
        public int GetCacheCount()
        {
            return _messageQueue.Count;
        }
        
        /// <summary>
        /// 添加缓存消息到缓存
        /// </summary>
        /// <param name="cachedMessage">缓存消息</param>
        /// <returns>是否添加成功</returns>
        public async Task<bool> AddMessageAsync(CachedMessage cachedMessage)
        {
            try
            {
                if (cachedMessage == null)
                {
                    return false;
                }

                await _cacheLock.WaitAsync();

                // 检查缓存是否已满
                if (_messageQueue.Count >= _maxCacheSize)
                {
                    // 移除最旧的消息
                    RemoveOldestMessage();
                }

                // 添加到内存队列
                _messageQueue.Add(cachedMessage);

                // 保存到文件
                await SaveMessageToFileAsync(cachedMessage);

                _logger.Debug($"添加缓存消息到缓存，消息ID: {cachedMessage.MessageId}, 主题: {cachedMessage.Topic}");
                return true;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"添加缓存消息到缓存失败，消息ID: {cachedMessage?.MessageId}");
                return false;
            }
            finally
            {
                _cacheLock.Release();
            }
        }

        /// <summary>
        /// 加载缓存消息
        /// </summary>
        private async Task LoadCachedMessagesAsync()
        {
            try
            {
                if (!Directory.Exists(_cacheDirectory))
                {
                    return;
                }

                // 获取所有缓存文件
                var files = Directory.GetFiles(_cacheDirectory, "*.msg");
                foreach (var file in files)
                {
                    try
                    {
                        // 读取文件内容
                        string json = await Task.Run(() => File.ReadAllText(file));
                        var message = JsonHelper.Deserialize<CachedMessage>(json);
                        if (message != null)
                        {
                            _messageQueue.Add(message);
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex, $"加载缓存消息失败: {file}");
                    }
                }

                _logger.Info($"已加载 {_messageQueue.Count} 条缓存消息");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "加载缓存消息失败");
            }
        }

        /// <summary>
        /// 保存消息到文件
        /// </summary>
        /// <param name="message">缓存消息</param>
        private async Task SaveMessageToFileAsync(CachedMessage message)
        {
            try
            {
                if (!Directory.Exists(_cacheDirectory))
                {
                    Directory.CreateDirectory(_cacheDirectory);
                }

                // 生成文件路径
                string filePath = Path.Combine(_cacheDirectory, $"{message.Id}.msg");

                // 序列化消息
                string json = JsonHelper.Serialize(message);

                // 写入文件
                await Task.Run(() => File.WriteAllText(filePath, json));
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"保存消息到文件失败，消息ID: {message.MessageId}");
            }
        }

        /// <summary>
        /// 删除消息文件
        /// </summary>
        /// <param name="id">缓存消息ID</param>
        private void DeleteMessageFile(string id)
        {
            try
            {
                string filePath = Path.Combine(_cacheDirectory, $"{id}.msg");
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"删除消息文件失败，缓存ID: {id}");
            }
        }

        /// <summary>
        /// 移除最旧的消息
        /// </summary>
        private void RemoveOldestMessage()
        {
            try
            {
                if (_messageQueue.Count == 0)
                {
                    return;
                }

                // 找到最旧的消息
                var oldestMessage = _messageQueue.OrderBy(m => m.Timestamp).First();

                // 从队列中移除
                _messageQueue.Remove(oldestMessage);

                // 删除文件
                DeleteMessageFile(oldestMessage.Id);

                _logger.Debug($"移除最旧的消息，消息ID: {oldestMessage.MessageId}");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "移除最旧的消息失败");
            }
        }
    }

    /// <summary>
    /// 缓存消息
    /// </summary>
    public class CachedMessage
    {
        /// <summary>
        /// 缓存ID
        /// </summary>
        public string Id { get; set; }

        /// <summary>
        /// 消息ID
        /// </summary>
        public string MessageId { get; set; }

        /// <summary>
        /// 消息类型
        /// </summary>
        public string MessageType { get; set; }

        /// <summary>
        /// 主题
        /// </summary>
        public string Topic { get; set; }

        /// <summary>
        /// 消息内容
        /// </summary>
        public string Payload { get; set; }

        /// <summary>
        /// 服务质量级别
        /// </summary>
        public int QosLevel { get; set; }

        /// <summary>
        /// 是否保留消息
        /// </summary>
        public bool Retain { get; set; }

        /// <summary>
        /// 时间戳
        /// </summary>
        public DateTime Timestamp { get; set; }

        /// <summary>
        /// 重试次数
        /// </summary>
        public int RetryCount { get; set; }
    }
} 